/**
 * 判断一个数是否为质数
 * @param {number} num 
 * @returns 
 */
function isPrime(num) {
  if (num <= 1) {
    return false;
  }
  if (num <= 3) {
    return true;
  }
  if (num % 2 === 0 || num % 3 === 0) {
    return false;
  }
  let i = 5;
  while (i * i <= num) {
    if (num % i === 0 || num % (i + 2) === 0) {
      return false;
    }
    i += 6;
  }
  return true;
}

/**
 * 随机生成一个质数
 * @param {number} min 
 * @param {number} max 
 * @returns 
 */
function generateRandomPrime(min = 3, max = 10000) {
  let num = Math.floor(Math.random() * (max - min + 1)) + min;
  while (!isPrime(num)) {
    num = Math.floor(Math.random() * (max - min + 1)) + min;
  }
  return num;
}

/**
 * 获取最大公约数
 * @param {number} a 
 * @param {number} b 
 * @returns 
 */
function gcd(a, b) {
  if (b === 0) {
    return a;
  }
  return gcd(b, a % b);
}

/**
 * x的m次方对n取模
 * @param {number} x 基数
 * @param {number} m 指数
 * @param {number} n 模数
 * @returns 
 */
// function powMod(x, m, n) {
//   let res = x % n
//   for (let i = 0; i < m - 1; i++) {
//     res = res * x % n
//   }
//   return res
// }
function powMod(x, m, n) {
  let result = 1; // 初始化结果为1
  x = (x) % (n); // 更新x以确保它在第一次乘法前已经在模n之下

  while (m > 0) {
    // 如果m是奇数，那么我们将当前的x乘到结果上，并对n取模
    if (m % 2 === 1) {
      result = (result * x) % n;
    }
    // 我们将x平方，并对n取模，准备下一轮循环
    x = (x * x) % n;
    // 将m除以2（向下取整），相当于移除最低位的比特
    m = Math.floor(m / 2);
  }

  return result;
}

function str2codes(str) {
  const codeArr = [];
  for (let i = 0; i < str.length; i++) {
    // 将字符串转换为UTF8编码的字节数组
    const codes = [...new TextEncoder().encode(str[i])]
    // 统一为3个字节(24位)
    for (let j = codes.length; j < 3; j++) {
      codes.unshift(0)
    }
    // 转换成24位二进制
    const binary = codes.map(code => code.toString(2).padStart(8, '0')).join('')
    codeArr.push(parseInt(binary, 2).toString());
  }
  return codeArr;
}

function codes2str(codeArr) {
  const str = [];
  for (let i = 0; i < codeArr.length; i++) {
    // 将24位二进制转换成3个字节
    const binary = parseInt(codeArr[i]).toString(2).padStart(24, '0')
    // 将二进制转换成UTF8编码的字节数组
    const codes = [];
    for (let j = 0; j < 24; j += 8) {
      const num = parseInt(binary.slice(j, j + 8), 2)
      if (codes.length || num !== 0) codes.push(num)
    }

    // 将字节数组转换为字符串
    const c = new TextDecoder().decode(new Uint8Array(codes))
    str.push(c)
  }
  return str.join('');
}


module.exports = { isPrime, generateRandomPrime, gcd, powMod, str2codes, codes2str }